<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Apps\Apis\Common\DefCtl;

use Srv\Libs\Common\CommTime;
use Srv\Libs\Frame\ControllerAbstract;
use Srv\Libs\Storage\DataMysql;

abstract class DefAbstract extends ControllerAbstract
{
    private ?DataMysql $DbAuto              = null;     // DB-Write
    private int $cacheTime                  = 600;      // 缓存时长[秒][0-长期][<0-不缓存]
    private int $cacheLastTime              = 0;        // 缓存的数据最后时间
    private array $cacheDataList            = [];       // 缓存的数据列表
    private array $cacheIdxList             = [];       // 缓存的索引列表
    private bool $isConfig                  = false;    // 是否已配置
    public const IDX_ID                     = 'id';
    public const IDX_KEY                    = 'key';
    private string $tableName               = '';
    private string $fieldId                 = '';
    private string $fieldKey                = '';
    private array $fieldExtList             = [];

    /**
     * @return static
     * tag
     */
    public static function tag():self
    {
        $thisObject                         = self::tagGet();
        if($thisObject instanceof self){
            $thisObject->DbAuto             = self::getDbAuto();
        }
        return $thisObject;
    }

    /**
     * @param string $tableName
     * @param string $fieldId
     * @param string $fieldKey
     * @param array $fieldExtList
     * @return $this
     * config
     */
    protected function config(string $tableName, string $fieldId, string $fieldKey, array $fieldExtList = []):self
    {
        if($this->isConfig) return $this;
        if(isset($fieldExtList[self::IDX_ID])) unset($fieldExtList[self::IDX_ID]);
        if(isset($fieldExtList[self::IDX_KEY])) unset($fieldExtList[self::IDX_KEY]);
        $this->tableName        = $tableName;
        $this->fieldId          = $fieldId;
        $this->fieldKey         = $fieldKey;
        $this->fieldExtList     = $fieldExtList;
        $this->loadData(true);
        $this->isConfig         = true;
        return $this;
    }

    /**
     * @param bool $isForce
     * @return bool
     * loadData
     */
    public function loadData(bool $isForce):bool
    {
        if(strlen($this->tableName) < 1 || strlen($this->fieldId) < 1 || strlen($this->fieldKey) < 1) return false;
        $currTime               = 0;
        if(!$isForce && $this->cacheLastTime > 0){
            if($this->cacheTime === 0) return true;
            $currTime           = CommTime::getTimeStamp();
            if(($currTime - $this->cacheLastTime) < $this->cacheTime) return true;
        }
        if($currTime < 1) $currTime = CommTime::getTimeStamp();
        $this->cacheLastTime    = $currTime;
        $this->cacheDataList    = [];
        $this->cacheIdxList     = [];
        $fieldExtListSize       = count($this->fieldExtList);
        $fieldExtStr            = '';
        if($fieldExtListSize > 0) foreach ($this->fieldExtList as $keyName => $fieldName) $fieldExtStr .= ', `'.$fieldName.'` AS '.$keyName;
        $isFail                 = false;
        $listData               = $this->DbAuto->getData('SELECT `'.$this->fieldId.'` AS _def_id, `'.$this->fieldKey.'` AS _def_key'.$fieldExtStr.' FROM '.$this->DbAuto->getTableNameAll($this->tableName), $isFail);
        if($isFail) return false;
        if(count($listData) > 0) foreach($listData as $listItem){
            $idItem             = intval($listItem['_def_id']??0);
            $keyItem            = $listItem['_def_key']??'';
            if($idItem < 1 || strlen($keyItem) < 1) continue;
            $keyItemData        = [self::IDX_ID => $idItem, self::IDX_KEY => $keyItem];
            if($fieldExtListSize > 0) foreach ($this->fieldExtList as $keyName => $fieldName){
                if(!isset($keyItemData[$keyName])) $keyItemData[$keyName] = $listItem[$keyName]??'';
            }
            $this->cacheDataList[$keyItem]  = $keyItemData;
            $this->cacheIdxList[$idItem]    = $keyItem;
        }
        return true;
    }

    /**
     * @param string $key
     * @param array $extData
     * @return int
     * getCreateId
     */
    private function getCreateId(string $key, array $extData = []):int
    {
        $id                 = $this->DbAuto->getDataInt('SELECT `'.$this->fieldId.'` AS _def_id FROM '.$this->DbAuto->getTableNameAll($this->tableName).' WHERE `'.$this->fieldKey.'`=\''.$this->DbAuto->getRealEscapeString($key).'\'', '_def_id');
        if($id > 0){
            $this->loadData(true);
            return $id;
        }
        $extSetStr          = '';
        if(count($extData) > 0) foreach ($extData as $extKey => $extVal){
            if($extKey === $this->fieldKey || $extKey === $this->fieldId) continue;
            if(is_int($extVal)){
                $extSetStr  .= ', `'.$extKey.'`='.$extVal;
            }else if(is_string($extVal)){
                $extSetStr  .= ', `'.$extKey.'`=\''.$this->DbAuto->getRealEscapeString($extVal).'\'';
            }else if(is_float($extVal)){
                $extSetStr  .= ', `'.$extKey.'`=\''.$this->DbAuto->getRealEscapeString(strval($extVal)).'\'';
            }
        }
        $id                 = $this->DbAuto->getDataId('INSERT INTO '.$this->DbAuto->getTableNameAll($this->tableName).' SET `'.$this->fieldKey.'`=\''.$this->DbAuto->getRealEscapeString($key).'\''.$extSetStr);
        $this->loadData(true);
        if($id > 0) return $id;
        return $this->cacheDataList[$key][self::IDX_ID]??0;
    }

    /**
     * @param string $key
     * @param array $extData
     * @return int
     * getIdByKeyCreate
     */
    public function getIdByKeyCreate(string $key, array $extData = []):int
    {
        if(strlen($key) < 1) return 0;
        $id     = $this->getIdByKey($key);
        if($id > 0) return $id;
        return $this->getCreateId($key, $extData);
    }

    /**
     * @param string $key
     * @param array $extData
     * @return array
     * getDataByKeyCreate
     */
    public function getDataByKeyCreate(string $key, array $extData = []):array
    {
        if(strlen($key) < 1) return [];
        $data   = $this->getDataByKey($key);
        if(count($data) > 0) return $data;
        if($this->getCreateId($key, $extData) < 1) return [];
        return $this->getDataByKey($key);
    }

    /**
     * @return array
     * getDataList
     */
    public function getDataList():array
    {
        return $this->cacheDataList;
    }

    /**
     * @param string $key
     * @return int
     * getIdByKey
     */
    public function getIdByKey(string $key):int
    {
        if(strlen($key) < 1) return 0;
        return $this->cacheDataList[$key][self::IDX_ID]??0;
    }

    /**
     * @param int $id
     * @return string
     * getKeyById
     */
    public function getKeyById(int $id):string
    {
        if($id < 1) return '';
        return $this->cacheDataList[strval($this->cacheIdxList[$id]??'')][self::IDX_KEY]??'';
    }

    /**
     * @param string $key
     * @return array
     * getDataByKey
     */
    public function getDataByKey(string $key):array
    {
        if(strlen($key) < 1) return [];
        return $this->cacheDataList[$key]??[];
    }

    /**
     * @param int $id
     * @return array
     * getDataById
     */
    public function getDataById(int $id):array
    {
        if($id < 1) return [];
        return $this->getDataByKey($this->cacheIdxList[$id]??'');
    }

    /**
     * @param string $key
     * @param string $extName
     * @param bool $isSet
     * @return string
     * getExtStrByKey
     */
    public function getExtStrByKey(string $key, string $extName, bool &$isSet = false):string
    {
        if(strlen($key) < 1) return '';
        $isSet      = isset($this->cacheDataList[$key][$extName]);
        return strval($this->cacheDataList[$key][$extName]??'');
    }

    /**
     * @param int $id
     * @param string $extName
     * @param bool $isSet
     * @return string
     * getExtStrById
     */
    public function getExtStrById(int $id, string $extName, bool &$isSet = false):string
    {
        if($id < 1) return '';
        $key        = $this->cacheIdxList[$id]??'';
        $isSet      = is_string($key) && strlen($key) > 0;
        if(!$isSet) return '';
        $isSet      = isset($this->cacheDataList[$key][$extName]);
        return strval($this->cacheDataList[$key][$extName]??'');
    }

    /**
     * @param array $idList
     * @param string $extName
     * @return array
     * getExtStrByIdBatch
     */
    public function getExtStrByIdBatch(array $idList, string $extName):array
    {
        if(count($idList) < 1) return [];
        $listData   = [];
        foreach ($idList as $id){
            $key            = $this->cacheIdxList[$id]??'';
            if(!(is_string($key) && strlen($key) > 0)) continue;
            $extNameVal     = strval($this->cacheDataList[$key][$extName]??'');
            if(strlen($extNameVal) < 1) continue;
            $listData[$id]  = $extNameVal;
        }
        return $listData;
    }

    /**
     * @param string $key
     * @param string $extName
     * @param bool $isSet
     * @return int
     * getExtIntByKey
     */
    public function getExtIntByKey(string $key, string $extName, bool &$isSet = false):int
    {
        if(strlen($key) < 1) return 0;
        $isSet      = isset($this->cacheDataList[$key][$extName]);
        return intval($this->cacheDataList[$key][$extName]??0);
    }

    /**
     * @param int $id
     * @param string $extName
     * @param bool $isSet
     * @return int
     * getExtIntById
     */
    public function getExtIntById(int $id, string $extName, bool &$isSet = false):int
    {
        if($id < 1) return 0;
        $key        = $this->cacheIdxList[$id]??'';
        $isSet      = is_string($key) && strlen($key) > 0;
        if(!$isSet) return 0;
        $isSet      = isset($this->cacheDataList[$key][$extName]);
        return intval($this->cacheDataList[$key][$extName]??0);
    }
}